
+function($) {
	/*!
	 * DataTables封装(参数通过data-options配置)
	 * 赵卉华, 2015-02-12, 2016-10-18
	 */
	// 修改报错的方式
	$.fn.dataTableExt.errMode = "throw";
	/**
	 * -------------------------------------------------------------
	 * // 初始化, 参数通过data-xxx配置在<table>上, 列参数配置在<th>上
	 * // <table data-table="options"> // 会自动初始化
	 * // $("table.yyy").xtable(options); // 手动初始化
	 * // options={method:'POST',url:'xx.json',params:{xxx:yyy}}
	 * -------------------------------------------------------------
	 * var api = $("table.yyy").xtable("api");
	 *
	 * api.reload(url, params); // 从服务器请求数据
	 * api.reload(url, params, false); // 从服务器请求数据, false=不重置分页
	 * api.reload(params); // 从服务器请求数据, params=请求参数JSON
	 * api.reload(params, false); // 从服务器请求数据, params=请求参数JSON, false=不重置分页
	 * api.reload(data); // 加载数据, data=JSON数组
	 *
	 * api.selected(); // 返回JSON对象
	 * api.selected(field); // 返回JSON对象的指定字段, 如: field="contact.email"
	 * api.selections(); // 返回JSON数组
	 * api.selections(field); // 返回JSON指定字段的数组, 如: field="contact.email"
	 * -------------------------------------------------------------
	 * 声明自定义渲染函数
		+function($) {
			// 自定义DataTable渲染函数
			$.fn.xtable.render.add("{user.site}", {
				render : function(data) {
					return '<a href="' + data.site + '">个人主页</a>';
				}
			});
		}(jQuery);
	 * 引用自定义渲染函数
	 * <th data-options="field:'site',render:'{user.site}'">个人主页</th>
	 * -------------------------------------------------------------
	 */
	$.fn.xtable = function(type, options) {
		if (type == null) {
			options = {}; type = "init";
		} else if ($.isPlainObject(type)) {
			options = type; type = "init";
		} else if (typeof(type) != "string") {
			return this; // 参数既不是选项也不是string, 什么也不干
		}
		var method = $.fn.xtable.methods[type];
		if (!method) {
			$.log.error("$.fn.xtable.methods." + type + " not found!");
			return this;
		}
		if (type == "init") {
			return this.each(function() {
				method.call(this, options);
			});
		} else {
			return method.apply(this[0], Array.prototype.splice.call(arguments, 1));
		}
	};
	
	var bindEvent = function() {
		var me = $(this);
		// 修改AJAX返回的JSON数据的机会
		me.on("xhr.dt", function(e, settings, json) {
			var me = $(this);
			if (json) {
				var count = $.zhh.field(json, settings.oInit.totalField);
				var list = $.zhh.field(json, settings.oInit.listField);
				json.recordsTotal = json.recordsFiltered = count;
				json.data = list;
			}
			settings.oAjaxResponse = json;

			// 重新加载数据时清空全选按钮
			me.find(selector).prop("checked", false);
		});
		// 选中行
		me.on("click.DataTables.selectRow", "tbody tr", function (e) {
			if ($(e.target).closest(".checkbox-skip").length > 0) { return; }

			var me = $(this);
			var table = me.closest("table");
			var api = table.xtable("api");
			if(me.find("td:first-child:not(.checkbox-normal) input[type=checkbox],td.checkbox-column input[type=checkbox]").is(":disabled")) { return; }
			var checked = me.is(".selected");
			me.toggleClass("selected")
				.find("td:first-child:not(.checkbox-normal) input[type=checkbox]:not(:disabled), td.checkbox-column input[type=checkbox]:not(:disabled)")
				.prop("checked", !checked);
			if (api.settings().init().selection == "single") {
				table.find(selector).prop("checked", false);
				me.siblings("tr.selected").removeClass("selected")
					.find("td:first-child:not(.checkbox-normal) input[type=checkbox]:not(:disabled), td.checkbox-column input[type=checkbox]:not(:disabled)")
					.prop("checked", false);
			}
		});
		// 全选/全不选
		var selector =  "thead td:first-child:not(.checkbox-normal) input[type=checkbox], " +
						"thead th:first-child:not(.checkbox-normal) input[type=checkbox], " +
						"thead td.checkbox-column input[type=checkbox], " +
						"thead th.checkbox-column input[type=checkbox]";
		me.on("click.DataTables.selectAll", selector, 
		function(e) {
			var me = $(this);
			if (me.is(":disabled")) { return; }
			me.selectall(function(checkbox, checked) {
				checkbox.closest("tr")[checked ? "addClass" : "removeClass"]("selected");
			});
		});
	};

	var RENDER = {
		"{index}": {
			"class": "text-center index-column",
			sortable: false,
			render: function(value, type, data, meta) {
				return meta ? meta.row + 1 : "&nbsp;";
			}
		},
		"{checkbox}": {
			"class": "text-center checkbox-column",
			sortable: false,
			render: function(value, type, data, meta) {
				if (meta && meta.settings) {
					var columns = meta.settings.aoColumns;
					var column = columns[meta.col];
					var fieldName = column.data;
					return '<input type="checkbox" name="' + fieldName + '" value="' + (value||'') + '" />';
				} else {
					return '<input type="checkbox" />';
				}
			}
		},
		"{template}": {
			// data-options="field:'operate',render:'{template}'"
			// data-options="field:'operate',render:'{template}',panel:'.main-panel'"
			// panel默认为body, panel:'this'=wrapper, panel:'parent'=父节点, panel:'selector'=wrapper.closest(selector)
			render: function(value, type, data, meta) {
				if ($.fn.template && meta && meta.settings) {
					var wrapper = $(meta.settings.nTableWrapper);
					var columns = meta.settings.aoColumns;
					var column = columns[meta.col];
					var fieldName = column.data;
		    		var panel = OPTIONS.fn.findPanel(wrapper, column.panel);
					var index = meta.row;
					if (meta.settings.oAjaxData.page != null && meta.settings.oAjaxData.rows != null) {
						index = ( meta.settings.oAjaxData.page - 1 ) * meta.settings.oAjaxData.rows + meta.row;
					}
					return panel.template(fieldName, $.extend(true, { i:index }, data));
				} else {
					return "&nbsp;";
				}
			}
		}
	};
	// 提供方法从外部注册RENDER
	$.fn.xtable.render = {
		add: function(field, options) {
			RENDER[field] = options;
		},
		del: function(field) {
			delete RENDER[field];
		}
	};
	$.fn.xtable.defaults = { totalField: "total", listField: "body" };

	$.fn.xtable.methods = {
		api: function() {
			return $(this).DataTable();
		},
		options: function() {
			return config.call(this);
		},
		init: function(options) {
			var o = config.call(this, options);
			if (o.ajax || o.ajaxSource || o.sAjaxSource) {
				o.bServerSide = true;
			}
			if (o.topn) {
				o.paging = false;
			}
			if (!o.bLengthChange && !o.bFilter) {
				o.dom =
					// "<'row'<'col-sm-6'l><'col-sm-6'f>>" +
					"<'row'<'col-sm-12'tr>>" +
					(o.topn ? "" : "<'row'<'col-sm-5'i><'col-sm-7'p>>");
			} else {
				if (o.topn) { // 取TOPn, 不分页, 也不显示共几页
					o.dom =
						"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
						"<'row'<'col-sm-12'tr>>";
				}
			}
			$(this).dataTable(o);
			bindEvent.call(this);
		}
	};

	// 根据data-api生成DataTables的调用参数
	var KEY = "data-table-options";
	var config = function(options) {
		var me = $(this);
		var o = me.data(KEY);
		if (o) { return o; }

		// 取<table>上的配置数据
		o = me.zoptions("table");
		convert(o, { limit:"displayLength", url:"ajax", method:"serverMethod" });

		// 取<th>上的配置数据
		var columns = [];
		me.find("> thead > tr").children("td, th").each(function() {
			var column = $(this).zoptions("options");
			convert(column, { "field":"data" });
			if (column.template) {
				$.extend(true, column, RENDER["template"]);
			} else if (column.render && RENDER[column.render]) {
				// 用render的参数覆盖data-options参数
				$.extend(true, column, RENDER[column.render]);
			}
			// sorting:"asc,desc"
			if ($.dt.isString(column.sorting)) {
				column.asSorting = column.sorting.split(/[,|]/g);
			} else if ($.dt.isArray(column.sorting)) {
				column.asSorting = column.sorting;
			}
			// 如果指定了sorting, 则允许排序
			if (column.asSorting) {
				column.sortable = true;
			}
			// 如果不允许排序, 则aDataSort设置为空数组, 否则第1列会出现排序的标记
			if (!column.sortable && !column.aDataSort) {
				column.aDataSort = [];
			}
			columns.push(column);
		});

		$.extend(o, {
			columns:columns,
			stripeClasses:[], // 不需要奇偶行分色 ["odd", "even"]
			serverParams: serverParams
		}, $.fn.xtable.defaults, options);
		me.data(KEY, o);
		return o;
	};
	// 转换参数
	// { limit:"displayLength", url:"ajax", method:"serverMethod" }
	var convert = function(options, data) {
		for (var key in data) {
			if (options[data[key]] == undefined && options[key] !=undefined) {
				options[data[key]] = options[key];
				delete options[key];
			}
		}
	};

	// 修改提交参数的机会
	var serverParams = function(data) {
		var old = $.extend(true, {}, data);
		// 由于return新参数无效, 只能把data的参数全部删除再重新添加, 以达到修改的目的
		for (var key in data) { delete data[key]; }

		var settings = this.fnSettings();
		// 修改参数
		if (settings.oInit.topn) { // 取TOPn
			data.page = 1;
			data.rows = settings.oInit.topn;
		} else if (old.length > 0) {
			data.page = old.start / old.length + 1;
			data.rows = old.length;
		}

		// 获取排序字段, order=[ { column:number, dir:asc/desc } ]
		if (old.order && $.isArray(old.order) && old.order.length > 0) {
			var orderings = [];
			$.each(old.order, function() {
				var column = old.columns[this.column];
				orderings.push(column.data + " " + this.dir.toUpperCase());
			});
			data.ordering = orderings.join(",");
		}
		// 追加params
		var params = settings.oInit && settings.oInit.params;
		if (params) { $.extend(data, params); }
		var fixedParams = settings.oInit && settings.oInit.fixedParams;
		if (fixedParams) { $.extend(data, fixedParams); }
		// 通过form读取参数
		var formSelector = settings.oInit && settings.oInit.formParams;
		if (formSelector) {
			var wrapper = $(settings.nTableWrapper);
    		var panel = OPTIONS.fn.findPanel(wrapper, settings.oInit && settings.oInit.panel);
    		var form = panel.find(formSelector);
    		var json = form.serializeJson();
    		if (json) { $.extend(data, json); }
		}
		// 读取模板参数
		var templateParams = settings.oInit && settings.oInit.templateParams;
		if (templateParams) {
			var wrapper = $(settings.nTableWrapper);
			var panel = OPTIONS.fn.findPanel(wrapper, settings.oInit && settings.oInit.panel);
			for (var key in templateParams) {
				var text = panel.find(templateParams[key]).text();
				if (text) { data[key] = text; }
			}
		}

		// 修改AJAX的URL地址, 替换{page}参数
		var ajax = settings.oInit && settings.oInit.ajax;
		var url = $.isPlainObject(ajax) ? ajax.url : ajax;
		var regexp = /\{p(age)?\}/g;
		if (url && typeof(url) == "string" && regexp.test(url)) {
			var api = this.api();
			var info = api.page.info();
			api.ajax.url(url.replace(regexp, info.page + 1));
		}
	};



	// dataTable功能增强
	var powered = false;
	$.fn.xtable.power = function(options) {
		if (!$.fn.dataTable || powered) { return; }
		powered = true;
		// 修改默认参数
		$.extend(true, $.fn.dataTable.defaults, OPTIONS, options);
		$.extend(true, $.fn.xtable.defaults, OPTIONS.xtable, options && options.xtable);
		/**
		 * api.selected(); // 返回JSON对象
		 * api.selected(field); // 返回JSON对象的指定字段, 如: field="contact.email"
		 */
		$.fn.dataTable.Api.register("selected()", function (field) {
			var array = this.rows(".selected").data().toArray();
			var json = array[0];
			if (json && field) {
				return $.zhh.field(json, field);
			} else {
				return json;
			}
		});
		/**
		 * api.selections(); // 返回JSON数组
		 * api.selections(field); // 返回JSON指定字段的数组, 如: field="contact.email"
		 */
		$.fn.dataTable.Api.register("selections()", function (field) {
			var array = this.rows(".selected").data().toArray();
			if (field) {
				var fields = [];
				$.each(array, function() {
					fields.push($.zhh.field(this, field))
				});
				return fields;
			} else {
				return array;
			}
		});
		var findByDataType = function(type, args) {
			if (!type || !args) { return undefined; }
			var method = "is" + type.charAt(0).toUpperCase() + type.substring(1);
			if (!$.dt[method]) { return undefined; }
			for (var i = 0; i < args.length; i++) {
				if ($.dt[method](args[i])) {
					return args[i];
				}
			}
			return undefined;
		};
		$.fn.dataTable.Api.register("reload()", function () {
			var array = findByDataType("array", arguments);
			var url = findByDataType("string", arguments);
			var params = findByDataType("PlainObject", arguments);
			var resetPaging = findByDataType("boolean", arguments);
			var fn = findByDataType("function", arguments);

			return this.iterator("table", function (settings) {
				// var me = $(settings.nTable);
				// var options = me.xtable("options");
				settings.oInit.params = $.extend(true, {}, params);
	
				if (array) { // 加载静态数据
					settings.oInit.ajax = null;
					settings.oFeatures.bServerSide = false;
					this.ajax.url(null);
					this.clear();
					this.rows.add(array);
				} else if (url) { // 加载AJAX数据
					settings.oInit.ajax = url;
					settings.oFeatures.bServerSide = true;
					this.ajax.url(url);
				}
				// 刷新当前分页
				this.draw(resetPaging);
				fn && fn.call(settings.nTable, settings);
			});
		});
	};
	var OPTIONS = {
		filter: false, // 是否启用过滤/搜索功能
		lengthChange: false, // 是否启用每页行数选择功能
		// sort: false, // 是否启用各个字段的排序功能
		orderClasses: false, // 是否给正在排序的列增加样式
		serverSide:false, // 是否启动服务器模式, 分页/排序都从服务器获取数据
		serverMethod:"POST",
		columnDefs: [ { defaultContent: "&nbsp;", sortable:false, targets: "_all" } ],
		language: undefined,
		xtable: { /* totalField: "xxx", listField: "yyy" */ },
		fn: {
			findPanel: function(element, selector) {
				if (!selector) return $(document.body);
				if (selector == "this") return element;
				if (selector == "parent") return element.parent();
				if (selector == "root") return $(document);
				if (selector == "body") return $(document.body);
				return element.closest(selector);
			}
		}
	};
}(jQuery);
